﻿//=======================================================
// Author: Jonas Follesø <jonas@follesoe.no>
// Copyright (c) 2008
//
// Licensed under the Microsoft Public License (Ms-PL)
// A copy of the license is available at 
// http://www.opensource.org/licenses/ms-pl.html
//=======================================================

using System;
using System.IO;
using System.Text;
using System.Windows;
using System.Windows.Media;
using System.IO.Packaging;
using System.Xml.Linq;

namespace Colorful.Control.Services
{
    public class CfXamlClipboardFormatter : ICopyColors
    {
        public string FormatName
        {
            get { return "cfXaml"; }
        }

        public void AddToClipboard(DataObject dataObject, Palette palette)
        {
            MemoryStream ms = new MemoryStream();
            Package zip = Package.Open(ms, FileMode.Create);

            PackagePart corePropertiesPart = zip.CreatePart(new Uri("/CoreProperties", UriKind.Relative), "text/Xml");
            using (Stream coreStream = corePropertiesPart.GetStream())
            {
                using (StreamWriter coreWriter = new StreamWriter(coreStream, Encoding.UTF8))
                {
                    coreWriter.Write("<?xml version='1.0' encoding='utf-8'?>\r\n<coreProperties\r\n  xmlns='http://schemas.microsoft.com/cfxaml/2006/06/metadata/core-properties'\r\n  xmlns:dc='http://purl.org/dc/elements/1.1'>\r\n  <contentType>cfXaml</contentType>\r\n  <dc:creator>Expression</dc:creator>\r\n  <version>0.71</version>\r\n</coreProperties>");
                }
            }
            zip.CreateRelationship(corePropertiesPart.Uri, TargetMode.Internal, "http://schemas.microsoft.com/cfxaml/2006/06/relationships/metadata/core-properties");

            AddContent(zip, CreatePaletteXaml(palette), 0);
            AddReference(zip, CreateResourceDictionary(palette), 0);

            zip.Flush();

            ms.Seek(0, SeekOrigin.Begin);            
            dataObject.SetData(FormatName, (Stream)ms, true);            
            zip.Close();            
        }

        private static void AddContent(Package zip, XElement xml, int n)
        {
            PackagePart rectPart = zip.CreatePart(new Uri("/CopiedItem" + n.ToString() + "/content.xaml", UriKind.Relative), "text/xml");
            using (Stream rectStream = rectPart.GetStream())
            {
                using (StreamWriter rectWriter = new StreamWriter(rectStream, Encoding.UTF8))
                {
                    rectWriter.Write(xml.ToString());
                }
            }
            zip.CreateRelationship(rectPart.Uri, TargetMode.Internal, "http://schemas.microsoft.com/cfxaml/2006/06/selected-item");
        }

        private static void AddReference(Package zip, XElement xml, int n)
        {
            PackagePart rectPart = zip.CreatePart(new Uri("/ReferencedItem" + n.ToString() + "/content.xaml", UriKind.Relative), "text/xml");
            using (Stream rectStream = rectPart.GetStream())
            {
                using (StreamWriter rectWriter = new StreamWriter(rectStream, Encoding.UTF8))
                {
                    rectWriter.Write(xml.ToString());
                }
            }
            zip.CreateRelationship(rectPart.Uri, TargetMode.Internal, "http://schemas.microsoft.com/cfxaml/2006/06/referenced-item");
        }

        private XElement CreatePaletteXaml(Palette palette)
        {
            var ns = XNamespace.Get("http://schemas.microsoft.com/winfx/2006/xaml/presentation");
            var mc = XNamespace.Get("http://schemas.openxmlformats.org/markup-compatibility/2006");
            var d = XNamespace.Get("http://schemas.microsoft.com/expression/blend/2008");
            var x = XNamespace.Get("http://schemas.microsoft.com/winfx/2006/xaml");

            string keyPrefix = GetPaletteName(palette);

            return new XElement(ns + "Grid",
                            new XAttribute("xmlns", ns.NamespaceName),
                            new XAttribute(XNamespace.Xmlns + "d", d.NamespaceName),
                            new XAttribute(XNamespace.Xmlns + "mc", mc.NamespaceName),
                            new XAttribute(XNamespace.Xmlns + "x", x.NamespaceName),
                            new XAttribute(mc + "Ignorable", "d"),    
                            new XAttribute(x + "Name", keyPrefix),
                            new XAttribute("Width", "160"),
                            new XAttribute("Height", "48"),
                            new XAttribute("Margin", "0,0,0,0"),
                            new XAttribute("VerticalAlignment", "Center"),
                            new XAttribute("HorizontalAlignment", "Center"),                            
                            new XAttribute(d + "LayoutOverrides", "HorizontalAlignment, VerticalAlignment"),
                            new XAttribute(d + "LayoutRect", "232,198,160,48"),
                            new XElement(ns + "Grid.ColumnDefinitions",
                                new XElement(ns + "ColumnDefinition"),
                                new XElement(ns + "ColumnDefinition"),
                                new XElement(ns + "ColumnDefinition"),
                                new XElement(ns + "ColumnDefinition"),
                                new XElement(ns + "ColumnDefinition")),
                            new XElement(ns + "Grid.RowDefinitions",
                                new XElement(ns + "RowDefinition",
                                    new XAttribute("Height", "Auto")),
                                new XElement(ns + "RowDefinition"),
                                    new XAttribute("Height", "*")),
                            new XElement(ns + "TextBlock",
                                new XAttribute("Text", palette.Name),
                                new XAttribute("Grid.Row", "0"),
                                new XAttribute("Grid.Column", "0"),
                                new XAttribute("Grid.ColumnSpan", "5")),
                            NewRectangle(ns, x, keyPrefix + "Color1", 0),
                            NewRectangle(ns, x, keyPrefix + "Color2", 1),
                            NewRectangle(ns, x, keyPrefix + "Color3", 2),
                            NewRectangle(ns, x, keyPrefix + "Color4", 3),
                            NewRectangle(ns, x, keyPrefix + "Color5", 4));
        }

        private XElement NewRectangle(XNamespace ns, XNamespace x, string colorName, int colorNummer)
        {
            return new XElement(ns + "Rectangle",
                new XAttribute(x + "Name", colorName),
                new XAttribute("Width", "Auto"),
                new XAttribute("Height", "Auto"),
                new XAttribute("StrokeThickness", "0"),
                new XAttribute("VerticalAlignment", "Stretch"),
                new XAttribute("HorizontalAlignment", "Stretch"),
                new XAttribute("Grid.Row", "1"),
                new XAttribute("Grid.Column", colorNummer.ToString()),
                new XAttribute("Fill", "{StaticResource " + colorName + "}"));
        }

        private XElement CreateResourceDictionary(Palette palette)
        {
            var ns = XNamespace.Get("http://schemas.microsoft.com/winfx/2006/xaml/presentation");
            var x = XNamespace.Get("http://schemas.microsoft.com/winfx/2006/xaml");

            string keyPrefix = GetPaletteName(palette);
            return new XElement(ns + "ResourceDictionary",
                new XAttribute("xmlns", ns.NamespaceName),
                new XAttribute(XNamespace.Xmlns + "x", x.NamespaceName),
                CreateSolidColorBrush(ns, x, keyPrefix + "Color1", palette.Color1),
                CreateSolidColorBrush(ns, x, keyPrefix + "Color2", palette.Color2),
                CreateSolidColorBrush(ns, x, keyPrefix + "Color3", palette.Color3),
                CreateSolidColorBrush(ns, x, keyPrefix + "Color4", palette.Color4),
                CreateSolidColorBrush(ns, x, keyPrefix + "Color5", palette.Color5));
        }

        private XElement CreateSolidColorBrush(XNamespace defaultNs, XNamespace x, string key, Color color)
        {
            return new XElement(defaultNs + "SolidColorBrush",
                    new XAttribute(x + "Key", key),
                    new XAttribute("Color", color.ToString()));
        }

        internal string GetPaletteName(Palette palette)
        {
            if (palette.Name.Length > 0 && Char.IsDigit(palette.Name[0]))
                return "c" + palette.Name.Replace(" ", "").Trim();
            else 
                return palette.Name.Replace(" ", "").Trim();
        }
    }
}
